package main

import (
	"bufio"
	"fmt"
	"io"
	"net"
	"os"
	"strconv"
	"strings"
)

const (
	UNDEFINED = iota
	EXIT
	RENAME
	PUBLICCHAT
	PRIVATECHAT
	QUERYUSER
)

type Client struct {
	Server string
	Port   int
	User   string
	conn   net.Conn
	doNum  int
}

func NewClient(server string, port int, user string) *Client {
	client := &Client{
		Server: server,
		Port:   port,
		User:   user,
		doNum:  UNDEFINED,
	}
	conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", server, port))
	if err != nil {
		panic(fmt.Sprintf("连接服务器失败: %v\n", err))
	}
	if len(user) > 0 {
		if _, err := conn.Write([]byte("rename " + user)); err != nil {
			fmt.Printf("修改用户名失败: %v\n", err)
		}
	}
	client.conn = conn
	return client
}

func (c *Client) menu() bool {
	fmt.Println("1. 退出")
	fmt.Println("2. 修改用户名")
	fmt.Println("3. 群发消息")
	fmt.Println("4. 私聊")
	fmt.Println("5. 查询在线用户")

	var str string
	fmt.Scanln(&str)
	num, err := strconv.Atoi(str)
	if err != nil {
		fmt.Printf("非法输入，请输入正确的菜单序号( 1 | 2 | 3 | 4 | 5 ), err: %v\n", err)
		return false
	}
	if num >= 1 && num <= 5 {
		c.doNum = num
		return true
	}
	fmt.Println("非法输入，请输入正确的菜单序号( 1 | 2 | 3 | 4 | 5 )")
	return false
}

func (c *Client) Rename() {
	fmt.Print("请输入用户名: ")
	fmt.Scan(&c.User)

	if len(c.User) == 0 {
		fmt.Println("请输入正确的用户名")
		return
	}

	msg := "rename " + c.User
	if _, err := c.conn.Write([]byte(msg)); err != nil {
		fmt.Printf("发送消息失败: %v\n", err)
	}
}

func (c *Client) PublicChat() {
	var msg string
	var err error
	for msg != "exit" {
		if len(msg) > 0 {
			if _, err := c.conn.Write([]byte(msg)); err != nil {
				fmt.Printf("发送消息失败: %v\n", err)
				break
			}
		}
		msg, err = input(">>>请输入聊天内容，'exit'退出群聊模式<<<")
		if err != nil {
			fmt.Printf("输入内容获取失败: %v\n", err)
		}
		fmt.Printf("msg: '%s'\n", msg)
	}
}

func (c *Client) PrivateChat() {
	var name string
	var msg string
	var err error
	for name != "exit" {
		if len(name) > 0 {
			tips := fmt.Sprintf(">>>请输入想对“%s”说的话，'exit'退出私聊模式<<<", name)
			for msg != "exit" {
				if len(msg) > 0 {
					if _, err := c.conn.Write([]byte(fmt.Sprintf("@%s %s", name, msg))); err != nil {
						fmt.Printf("向“%s”发送消息失败: %v\n", name, err)
					}
				}
				if msg, err = input(tips); err != nil {
					fmt.Printf("输入内容获取失败: %v\n", err)
				}
			}
		}
		c.QueryUser()
		name, err = input(">>>请输入聊天对象，'exit'退出私聊模式<<<")
		if err != nil {
			fmt.Printf("输入内容获取失败: %v\n", err)
			name = ""
		}
	}
}

func (c *Client) QueryUser() {
	msg := "who"
	if _, err := c.conn.Write([]byte(msg)); err != nil {
		fmt.Printf("查询在线用户失败: %v\n", err)
	}
}

func (c *Client) DialResponse() {
	for {
		buf := make([]byte, 4096)
		if _, err := c.conn.Read(buf); err == io.EOF{
			os.Exit(0)
		} else if err != nil {
			fmt.Printf("接收服务器消息失败: %v\n", err)
			os.Exit(1)
		}

		fmt.Print(string(buf))
	}

}

func (c *Client) Run() {
	for c.doNum != EXIT {
		if c.menu() != true {
			continue
		}
		switch c.doNum {
		case RENAME:
			c.Rename()
		case PUBLICCHAT:
			c.PublicChat()
		case PRIVATECHAT:
			c.PrivateChat()
		case QUERYUSER:
			c.QueryUser()
		}
	}
}

func input(tips string) (string, error) {
	buf := bufio.NewReader(os.Stdin)
	fmt.Println(tips)
	str, err := buf.ReadString('\n')
	if err != nil {
		return str, err
	}
	return strings.TrimSpace(str), nil
}
